package com.zhijian.wharf.config;

import com.zhijian.entity.CommonResult;
import com.zhijian.response.annotation.Response;
import com.zhijian.util.page.Page;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 自定义对外所有请求体
 *
 * @Author chengqing
 * @DateTime 2019年4月14日 下午3:43:07
 * @Version 1.0.1
 */
@SuppressWarnings("rawtypes")
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
public class ResponseJsonHandler implements HandlerMethodReturnValueHandler, InitializingBean {

    @Getter
    @Setter
    private HttpMessageConverter messageConverter;

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return returnType.getMethodAnnotation(Response.class) != null;
    }

    @SuppressWarnings({"unchecked"})
    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest) throws Exception {
        mavContainer.setRequestHandled(true);
        Map<String, Object> map = new HashMap<String, Object>();
        CommonResult resp = null;
        //如果有Response注解，则过滤返回的对象returnValue
        if (returnType.hasMethodAnnotation(Response.class)) {
            Response response = returnType.getMethodAnnotation(Response.class);
            //获取配置要过滤的字段
            String exclude = response.exclude();
            if (StringUtils.isNotEmpty(exclude)) {
                String[] excludes = exclude.split(",");
                if (returnValue instanceof Page) {
                    Page<Map<String, Object>> page = (Page<Map<String, Object>>) returnValue;
                    List<Map<String, Object>> data = page.getData();
                    for (Map<String, Object> m : data) {
                        //去除不包含的字段
                        getNewMapData(excludes, m);
                    }
                    resp = CommonResult.success(page);
                } else {
                    //将object转成map
                    map = getObjectToMap(returnValue);
                    //去除不包含的字段
                    getNewMapData(excludes, map);
                    resp = CommonResult.success(map);
                }
            } else {
                resp = CommonResult.success(returnValue);
            }
        } else {
            resp = CommonResult.success(returnValue);
        }
        messageConverter.write(resp, MediaType.APPLICATION_JSON_UTF8, new ServletServerHttpResponse(webRequest.getNativeResponse(HttpServletResponse.class)));
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (messageConverter == null) {
            throw new Exception("messageConverter is null");
        }
    }

    /**
     * 将object转成map
     *
     * @param object
     * @return
     */
    private Map<String, Object> getObjectToMap(Object object) throws IllegalAccessException {
        Map<String, Object> map = new HashMap<String, Object>();
        Class<?> aClass = object.getClass();
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String keyName = field.getName();
            Object value = field.get(object);
            if (value == null)
                value = "";
            map.put(keyName, value);
        }
        return map;
    }

    /**
     * 去除不包含的字段
     *
     * @param excludes
     * @param map
     */
    private void getNewMapData(String[] excludes, Map<String, Object> map) {
        for (int i = 0; i < excludes.length; i++) {
            Iterator<String> iter = map.keySet().iterator();
            while (iter.hasNext()) {
                if (iter.next().equals(excludes[i])) {
                    iter.remove();
                }
            }
        }
    }
}
